【PyTorch】构造VGG19网络进行本地图片分类(超详细过程) |
您所在的位置:网站首页 › pytorch 可视化网络结构 › 【PyTorch】构造VGG19网络进行本地图片分类(超详细过程) |
本篇博客主要解决以下3个问题: 如何自定义网络(以VGG19为例)。如何自建数据集并加载至模型中。如何使用自定义数据训练自定义模型。第一篇:【PyTorch】构造VGG19网络进行本地图片分类(超详细过程)——项目介绍 第二篇:【PyTorch】构造VGG19网络进行本地图片分类(超详细过程)——程序代码 Github:https://github.com/MarvelInSky/vgg_classify 文章目录 一、VGG简介二、数据集介绍三、项目程序3.1 测试环境3.2 程序结构3.3 常用函数3.3.1 Module类3.3.2 Dataset类3.3.3 DataLoader类3.3.4 损失函数3.3.5 优化器3.3.6 optimizer.zero_grad()3.3.7 net.train()与net.eval()3.3.8 保存与加载模型3.3.9 tensorboard3.3.10 tqdm动态进度条 四、Debug4.1 参数类型和模型权重类型不一致4.2 前项传播时卷积层内数据维度不匹配4.3 前项传播时全连接层数据维度不匹配4.4 GPU显存不足4.5 RGB图像中混入灰度图片4.6 训练过程中模型发散 参考博客 一、VGG简介VGG的网络结构如下,本篇博客以VGG19(E列),过多内容不再介绍。 二、数据集介绍Animal Image Dataset(DOG, CAT and PANDA) Dataset for Image Classification Practice 下载地址:https://www.kaggle.com/ashishsaxena2209/animal-image-datasetdog-cat-and-panda 该数据集共包含3类目标:狗、猫和熊猫;每种图片各1000张;图片尺寸不固定;大部分图片为RGB图片,少部分图片为灰度图片,所以在处理数据的时候要注意通道数。 将其分为train、test两个文件: train:用于训练模型,存放每种类别的第1至第900张图片,共包含2700张。test:用于验证和测试,存放每种类别的第901至第1000张图片,共包含300张。 三、项目程序 3.1 测试环境测试环境 Python3.8 Cuda10.1 PyTorch1.7所需依赖 matplotlib torch torchvision 3.2 程序结构 程序名称作用vgg_model.py继承torch.nn.Module创建VGG这个类,构造器(__int__())内创建了模型的结构,并创建前项传播的方法。vgg_dataset.py继承torch.utils.data.Dataset创建MyDataset这个类,用于加载我们所需要的的数据集。vgg_train.py设置参数,初始化模型,加载数据集,设置优化器、损失函数进行模型训练,并保存准确率高的模型。vgg_test.py调用已训练的模型对测试集进行测试。 3.3 常用函数 3.3.1 Module类自定义一个模型——通过继承nn.Module类来实现,需要在__init__构造函数中申明各层的定义,在forward中实现层之间的连接关系,实际上就是前向传播的过程。 import torch.nn as nn class VGG(nn.Module): # 初始化并定义网络结构 def __init__(): # 定义网络结构 def forward(self, x) # 前项传播的方法参考: https://blog.csdn.net/qq_27825451/article/details/90705328 3.3.2 Dataset类pytorch包里提供了Dataset来对数据进行加载,通过继承Dataset类得到MyDataset类,我们可以实现对自己数据集的加载。继承的类需要重写__init__、__len__、__getitem__。 __len__:返回数据内包含的数据总量,可以将所有数据的地址存储在一个列表里,返回字典的长度即刻。 __getitem__:根据对象的索引,返回(x,y),x为图像的数据,y为标签。 __init__:根据以上__len__和__getitem__的需求,可以将每张数据图片的路径存在一个list中,方便getitem的调用。 参考: https://blog.csdn.net/weixin_44168899/article/details/100929727 https://blog.csdn.net/leviopku/article/details/99958182 3.3.3 DataLoader类在上一步中,通过继承Dataset类得到MyDataset获得读取数据的方法,现在使用DataLoader加载这些类。 train_loader = DataLoader(dataset, batch_size, num_workers=2, shuffle=True)dataset:为实例化MyDataset得到的对象。 batchsize:就是每次从数据中心加载进模型的数量。 num_workers:相当于有两个线程在同时处理加载。 shuffle=True:表示加载数据的时候是乱序。 参考: https://blog.csdn.net/zw__chen/article/details/82806900 https://pytorch.org/docs/1.1.0/_modules/torch/utils/data/dataloader.html 3.3.4 损失函数定义:损失函数使用交叉熵 loss_function = torch.nn.CrossEntropyLoss()在每一batch中使用,计算误差并进行反向传播 loss = loss_function(outputs, labels) # outputs为模型得到的值,labels为真值 loss.backward() # 将loss进行反向传播表示使用交叉熵作为损失函数。 3.3.5 优化器定义:使用SGD优化器,scheduler自定义调整学习率 optimizer = torch.optim.SGD(net.parameters(), lr, momentum=0.9, weight_decay=5e-4) scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones, gamma=0.1)参考:https://blog.csdn.net/zisuina_2/article/details/103258573 3.3.6 optimizer.zero_grad()optimizer.zero_grad()意思是把梯度置零,即将loss关于weight的导数变成0. 参考:https://blog.csdn.net/scut_salmon/article/details/82414730 3.3.7 net.train()与net.eval()net.train():启用Batch Normalization和Dropout net.eval():不启用Batch Normalization和Dropout 参考:https://blog.csdn.net/qq_38410428/article/details/101102075 3.3.8 保存与加载模型 # 加载自定义模型 net = vgg_model.VGG(img_siz, input_channel, num_class) # 训练 ... # 训练完成后保存模型 torch.save(net.state_dict(), weights_path)net.state_dict()表示只保存模型中的参数,可以减小模型的体积。 # 加载自定义模型,此时里面参数是随机的 net = vgg_model.VGG(img_siz, input_channel, num_class) # 加载训练好的参数到模型 net.load_state_dict(torch.load(opt.model_path)) 3.3.9 tensorboardtensorboard可用于记录训练时的日志,可以在训练时,实时观看相关数据的变化曲线,了解模型的变化趋势。 from torch.utils.tensorboard import SummaryWriter # 开启记录 writer = SummaryWriter(log_dir) # 添加记录数据 for epoch in range(1,epochs) ... writer.add_scalar('Average loss', loss, epoch) writer.add_scalar('Accuracy', acc, epoch)使用方法: writer.add_scalar('曲线图名称', 纵坐标, 横坐标)查看方法: 在日志目录下打开终端输入命令:tensorboard --logdir=日志所在目录 启动后,在浏览器打开http://localhost:6006/ 。 3.3.10 tqdm动态进度条希望在每一batch都显示实时当前的epoch、loss和lr,但是又不希望不停的print的这些值,因为这些print会减慢训练速度,也不方便查看其它epoch的效果。所以使用tqdm库的创建动态的进度条。 # 获取数据的总量 nb = len(train_dataset) # 创建进度条 # train_loader 需要遍历的数据 # total=数据的总量,为总量/batchsize pbar = tqdm(enumerate(train_loader), total=int(nb / opt.batch_size)) # 在训练时 for step, (images, labels) in pbar: ...效果如下: 四、Debug 4.1 参数类型和模型权重类型不一致 RuntimeError: Input type (torch.cuda.FloatTensor) and weight type (torch.FloatTensor) should be the same原因:在编写项目的过程中,考虑了是否使用GPU的情况;所以,在传递传递参数时,如果使用GPU,则x=x.cuda(),然而在初始化模型时,没有使用cuda();这就导致参数的格式和初始化得到的模型中的权重格式不一致。 解决: net = vgg_model.VGG(input_channel=3, num_class=opt.num_class) # 改为 if opt.gpu: net = vgg_model.VGG(input_channel=3, num_class=opt.num_class).cuda() else: net = vgg_model.VGG(input_channel=3, num_class=opt.num_class) 4.2 前项传播时卷积层内数据维度不匹配 # 在卷积层处发生错误 RuntimeError: Given groups=1, weight of size [512, 512, 3, 3], expected input[16, 256, 28, 28] to have 512 channels, but got 256 channels instead原因:输入的尺寸和某一层的结构不匹配。 解决:在前项传播中,输出每一层的结构和每一层的输出结果,发现到第九层时出现错误,仔细观察每一层的input_channel和output_channel,发现第9成的网络输入输出为(512,512),此处由于疏忽写错了,将其改为(256, 512)即可。 4.3 前项传播时全连接层数据维度不匹配 # 在全连接层处发生错误 RuntimeError: mat1 dim 1 must match mat2 dim 0原因:在参考代码中,第一层全连接的代码:nn.Linear(512, 4096)是将512个数据转为4096个数据,采用的数据集为cifar100,其像素尺寸为32X32,经过16层卷积和5次池化,可将原尺寸[3,32,32]转变为[512,1,1],其中512X1X1=512。然而,我的数据集的像素尺寸已经resize成224X224,经过16个层卷积和5次池化,原尺寸[3,512,512]转变为[512,7,7],其中51277=25088,所以第一层全连接的代码为:nn.Linear(25088, 4096)。 解决:但是这样写兼容性就差了许多,不能兼容各像素的图片,所以将25088这个值改成由输入图片像素构成的: c o n v O u t = 512 × ( i m g S i z e / 24 ) 2 convOut = 512 \times(imgSize / 24)^2 convOut=512×(imgSize/24)2 4.4 GPU显存不足 cuda out of memory原因:电脑的显存不够。 解决:原本输入图像的尺寸为224224,现改为128128,原本的batchsize为8改为4。 4.5 RGB图像中混入灰度图片 RuntimeError: Given groups=1, weight of size [64, 3, 3, 3], expected input[1, 1, 64, 64] to have 3 channels, but got 1 channels instead原因:默认数据集中均位3通道图片(RGB图像),但其中有混入的单通道图片(灰度图片)。 解决:在使用Dataset加载数据时,判断是否为单通道,若为单通道图片则转为三通道图片。 4.6 训练过程中模型发散 Training Epoch: 1 [2/2700] Loss: 1.2244 LR: 0.100000 Training Epoch: 1 [4/2700] Loss: 20.7208 LR: 0.100000 Training Epoch: 1 [6/2700] Loss: 25.6863 LR: 0.100000 Training Epoch: 1 [8/2700] Loss: 0.0000 LR: 0.100000 Training Epoch: 1 [10/2700] Loss: 1070.9552 LR: 0.100000 Training Epoch: 1 [12/2700] Loss: 91453.2031 LR: 0.100000 Training Epoch: 1 [14/2700] Loss: 489251648.0000 LR: 0.100000 Training Epoch: 1 [16/2700] Loss: 372763991191060480.0000 LR: 0.100000 Training Epoch: 1 [18/2700] Loss: nan LR: 0.100000 Training Epoch: 1 [20/2700] Loss: nan LR: 0.100000 之后Loss均为nan原因:在训练的时候很快就开始发散了,模型未收敛。 解决:将学习率(Learning rate,lr)从0.1改为0.0001。 参考博客 pytorch实现vgg19 训练自定义分类图片:https://www.cnblogs.com/wuzaipei/p/12652932.htmlpytorch-cifar100: https://github.com/weiaicunzai/pytorch-cifar100yolov5:https://github.com/ultralytics/yolov5 |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |